﻿using System;
using System.Diagnostics.Contracts;

namespace CardPlay.Model.CardModel
{
    public class Card
    {
        private readonly CardFace _face;
        private CardOrientation _orientation = CardOrientation.FaceDown;

        public event EventHandler Flipped;

        public Card(Rank rank, Suit suit, int backDesign = 0) 
            : this(new CardFace(rank, suit), backDesign)
        {
        }

        public Card(CardFace face, int backDesign = 0)
        {
            Contract.Requires<ArgumentNullException>(face != null, "face");

            _face = face;
            _orientation = CardOrientation.FaceDown;

            BackDesign = backDesign;
        }

        public CardFace Face
        {
            get { return _face; }
        }
        
        public Rank Rank 
        {
            get { return Face.Rank; }
        }

        public Suit Suit 
        {
            get { return Face.Suit; }
        }

        public int BackDesign
        {
            get; private set;
        }

        public CardOrientation Orientation
        {
            get { return _orientation; }
            set
            {
                if (value == Orientation) return;

                _orientation = value;
                RaiseFlipped();
            }
        }
        
        public bool IsFaceUp
        {
            get { return _orientation == CardOrientation.FaceUp; }
            set { Orientation = value ? CardOrientation.FaceUp : CardOrientation.FaceDown; }
        }
        
        public void Flip()
        {
            IsFaceUp = ! IsFaceUp;
        }

        public override string ToString()
        {
            return String.Format(IsFaceUp ? "[{0}]" : "[{0} hidden]", Face);
        }

        public override int GetHashCode()
        {
            return BackDesign * CardFace.CardsPerStandardDeck + Face.GetHashCode();
        }

        public static implicit operator CardFace(Card card)
        {
            return card.Face;
        }

        private void RaiseFlipped()
        {
            var notify = Flipped;
            if (notify != null) notify(this, EventArgs.Empty);
        }
    }
}
